import traceback
import numpy as np
import math
from PyQt5 import QtGui, QtCore
from PyQt5.QtCore import QRectF, QPoint, QLine, QLineF, QEvent
from PyQt5.QtGui import QMouseEvent
from PyQt5.QtWidgets import QWidget

from cude_generator import CubeData


class SingleEyeWidget(QWidget):

    def __init__(self, parent):
        super(SingleEyeWidget, self).__init__(parent)
        self.cube_data: CubeData = None
        self.pos = 0

        self.setMouseTracking(True)
        # self.red_line_pen = QtGui.QPen(QtCore.Qt.GlobalColor.red, 1, QtCore.Qt.PenStyle.DashLine)
        self.red_line_pen = QtGui.QPen(QtCore.Qt.GlobalColor.red, 1, QtCore.Qt.PenStyle.SolidLine)
        self.is_show_result = False
        self.on_mouse_event = None
        self.shadow_circle = None
        self.ss_x, self.ss_y = 0, 0

    def set_mouse_listener(self, on_mouse_event):
        self.on_mouse_event = on_mouse_event

    def paintEvent(self, event: QtGui.QPaintEvent) -> None:

        qp = QtGui.QPainter()
        try:
            qp.begin(self)
            self.draw_content(qp)
        except Exception as e:
            print(e)
            traceback.print_exc()
        finally:
            qp.end()

    def draw_content(self, qp):
        # self.draw_test_rect(qp)

        if self.cube_data is None:
            return

        cube_size = self.cube_data.cube_size
        # randint_matrix = self.cube_data.randint_matrix_array[self.pos]
        randint_rgb_matrix = self.cube_data.randint_rgb_matrix_array[self.pos]
        h, w, c = randint_rgb_matrix.shape
        content_width = w * cube_size
        content_height = h * cube_size

        line_width = 3
        if self.pos == 0:
            start_x = math.floor(self.width() - content_width - line_width)
            start_y = math.floor((self.height() - content_height) * 0.5)
        else:
            start_x = math.floor(0)
            start_y = math.floor((self.height() - content_height) * 0.5)

        self.ss_x, self.ss_y = start_x, start_y

        # 白色背景
        qp.setPen(QtGui.QPen(QtCore.Qt.GlobalColor.white, line_width, QtCore.Qt.PenStyle.SolidLine))
        qp.setBrush(QtGui.QColor(0, 0, 0, 0))
        qp.drawRect(start_x - 1, start_y - 1, content_width + 1, content_height + 1)
        self.setMinimumWidth(content_width + (2 * line_width))
        self.setMinimumHeight(content_height + (2 * line_width))

        # 彩色格子
        qp.setPen(QtCore.Qt.GlobalColor.transparent)
        for row in range(h):
            for col in range(w):
                # color_index = randint_matrix[row, col]
                # color_value = CubeData.COLOR_ARRAY[color_index]
                color_value = randint_rgb_matrix[row, col]
                qp.setBrush(QtGui.QColor(*color_value))
                x, y = col * cube_size, row * cube_size
                qp.drawRect(start_x + x, start_y + y, cube_size, cube_size)

        # 黑色分割线
        if self.cube_data.border_size > 0:
            qp.setPen(QtGui.QPen(QtCore.Qt.GlobalColor.black, self.cube_data.border_size, QtCore.Qt.PenStyle.SolidLine))
            row_lines = []
            for row in range(h + 1):
                y = start_y + row * cube_size
                row_lines.append(QLineF(start_x, y, start_x + content_width, y))
            qp.drawLines(row_lines)

            col_lines = []
            for col in range(w + 1):
                x = start_x + col * cube_size
                col_lines.append(QLineF(x, start_y, x, start_y + content_height))
            qp.drawLines(col_lines)

        # 把已经找到的镶个金边
        qp.setPen(QtGui.QPen(QtGui.QColor(255, 215, 0), self.cube_data.border_size + 2, QtCore.Qt.PenStyle.SolidLine))
        qp.setBrush(QtGui.QColor(0, 0, 0, 0))
        if len(self.cube_data.diff_arr_founded) > 0:
            for target in self.cube_data.diff_arr_founded:
                row, col = target
                x, y = col * cube_size, row * cube_size
                qp.drawRect(start_x + x, start_y + y, cube_size, cube_size)

        self.draw_diff_result(qp, start_x, start_y)

        self.draw_shadow_circle(qp, start_x, start_y)

    def draw_shadow_circle(self, qp, start_x, start_y):
        if self.shadow_circle is None:
            return
        radius = 16
        qp.setPen(QtGui.QPen(QtGui.QColor(0, 0, 0), 3, QtCore.Qt.PenStyle.SolidLine))
        qp.setBrush(QtGui.QColor(0, 0, 0, 0))

        qp.drawEllipse(self.shadow_circle.x() + start_x - radius * 0.5,
                       self.shadow_circle.y() + start_y - radius * 0.5,
                       radius, radius)

    def draw_diff_result(self, qp, start_x, start_y):

        if not self.is_show_result:
            return

        cube_size = self.cube_data.cube_size
        qp.setPen(QtGui.QPen(QtGui.QColor(0, 233, 233), 3, QtCore.Qt.PenStyle.SolidLine))
        qp.setBrush(QtGui.QColor(0, 0, 0, 0))
        for target in self.cube_data.diff_arr:
            row, col = target
            x, y = col * cube_size, row * cube_size
            qp.drawEllipse(QPoint(int(start_x + x + cube_size * 0.5), int(start_y + y + cube_size * 0.5)),
                           int((cube_size + 2) * 1.3), int((cube_size + 2) * 1.3))

    def init(self, cube_data: CubeData, pos: int):
        self.cube_data = cube_data
        self.pos = pos
        self.update()

    def show_diff_result(self, is_show_result):
        self.is_show_result = is_show_result
        self.update()

    def draw_test_rect(self, qp):
        qp.setPen(self.red_line_pen)
        qp.setBrush(QtGui.QColor(255, 255, 0, 10))
        qp.drawRect(0, 0, self.width() - 1, self.height() - 1)

    def trigger_mouse_event(self, event, c_pos, pos):
        # if pos == self.pos:
        #     return

        if event == 0:
            self.shadow_circle = c_pos
            self.update()

    def leaveEvent(self, a0: QtCore.QEvent) -> None:
        # print("--------leave")
        if self.cube_data is None:
            return

        self.on_mouse_event(0, None, self.pos)

    def handleMouseEvent(self, event: QMouseEvent):
        if self.cube_data is None:
            return

        if not self.cube_data.is_show_shadow:
            return

        type = event.type()
        button = event.button()
        x = event.x()
        y = event.y()

        c_pos = QPoint(x - self.ss_x, y - self.ss_y)

        # print("----------------: ", type)

        if type == QMouseEvent.Type.MouseMove:
            self.on_mouse_event(0, c_pos, self.pos)
        elif type == QEvent.MouseButtonPress:
            if button != 1:
                return
            self.cube_data.check_pos(c_pos)
            self.on_mouse_event(1, c_pos, self.pos)


    mousePressEvent = handleMouseEvent
    mouseMoveEvent = handleMouseEvent
    mouseReleaseEvent = handleMouseEvent
